#include <stdio.h>
#include <cpar.h>

static CPARContext *pGlobalContext;

typedef struct CPARGlobalStackData CPARGlobalStackData;

struct CPARGlobalStackData
{
  int A;
};

static CPARGlobalStackData *pGlobalStack;

typedef struct CPARTaskStackData_tarefa1 CPARTaskStackData_tarefa1;
struct CPARTaskStackData_tarefa1
{
  CPARSemaphore *s;
  cpar_atomic volatile i;
  volatile int B;
};

typedef struct CPARTaskStackData_tarefa2 CPARTaskStackData_tarefa2;
struct CPARTaskStackData_tarefa2
{
  cpar_atomic volatile i;
};

void CPARTask_tarefa1(CPARContext *pContext);
void CPARTask_tarefa2(CPARContext *pContext);

void CPARTask_tarefa1_CPARForAll_1(CPARContext *pContext)
{
  CPARTaskStackData_tarefa1 *pStack;
  pStack = (CPARTaskStackData_tarefa1*) CPARContextStackGet(pContext);

  while(CPARAtomicInc(&(pStack->i)) <= 10000)
  {
    CPARSemaphoreLock(pStack->s);
    pStack->B = pStack->B + 1;
    CPARSemaphoreUnlock(pStack->s);
    printf("b=%d ",pStack->B);
    fflush(stdout); 
  }
}

void CPARTask_tarefa1(CPARContext *pContext)
{
  CPARTaskStackData_tarefa1 *pStack;

  pStack = (CPARTaskStackData_tarefa1*) CPARContextStackGet(pContext);

  CPARSemaphoreCreate(CPARContextAllocatorGet(pContext), &(pStack->s), 1);

  printf("inicio\n");
  fflush(stdout); 

  pStack->i = 1;
  CPARContextForAll(pContext,CPARTask_tarefa1_CPARForAll_1);

  CPARSemaphoreDestroy(pStack->s);
}

void CPARTask_tarefa2(CPARContext *pContext){
  CPARTaskStackData_tarefa2 *pStack;

  pStack = (CPARTaskStackData_tarefa2*) CPARContextStackGet(pContext);

  for (pStack->i=0;pStack->i<100;pStack->i++)
  {	
    printf("b");
    fflush(stdout);
  }
}

int main(int argc, char **argv)
{ 
  CPARInit();

  if( CPARContextCreate( NULL, &pGlobalContext, sizeof(CPARGlobalStackData) ))
  {
    CPAR_ERROR("Falha ao alocar contexto global");
    return CPAR_E_NO_MEMORY;
  }
  pGlobalStack = (CPARGlobalStackData*) CPARContextStackGet(pGlobalContext);

  if( CPARContextWorkPoolCreate( pGlobalContext, 3 ))
  {
    CPAR_ERROR("Falha ao alocar work pool");
    return -1;
  }

  pGlobalStack->A = 2;

  CPARContextTaskDispatch(pGlobalContext, 2, CPARTask_tarefa1, sizeof(CPARTaskStackData_tarefa1));

  CPARContextTaskDispatch(pGlobalContext, 1, CPARTask_tarefa2, sizeof(CPARTaskStackData_tarefa2));

  CPARContextTaskWaitAll(pGlobalContext);

  printf("\n FIM \n");

  fflush(stdout); 

  return CPAR_SUCCESS;
}
